<?php

namespace Kunfeng\Dify\Client\Impl;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Kunfeng\Dify\Callback\CompletionStreamCallback;
use Kunfeng\Dify\Client\DifyCompletionClientInterface;
use Kunfeng\Dify\Enum\ResponseMode;
use Kunfeng\Dify\Event\EventFactory;
use Kunfeng\Dify\Exception\DifyApiException;
use Kunfeng\Dify\Model\Completion\CompletionRequest;
use Kunfeng\Dify\Model\Completion\CompletionResponse;
use Kunfeng\Dify\Model\Common\SimpleResponse;

/**
 * Dify 文本生成型应用客户端实现
 */
class DifyCompletionClient extends AbstractDifyClient implements DifyCompletionClientInterface
{
    // API 路径常量
    private const COMPLETION_MESSAGES_PATH = '/completion-messages';
    private const TEXT_TO_AUDIO_PATH = '/text-to-audio';
    private const STOP_PATH = '/stop';

    public function __construct(string $baseUrl, string $apiKey, ?Client $httpClient = null)
    {
        parent::__construct($baseUrl, $apiKey, $httpClient);
    }

    /**
     * 发送文本生成请求（阻塞模式）
     */
    public function sendCompletionMessage(CompletionRequest $request): CompletionResponse
    {
        $data = $this->executePost(self::COMPLETION_MESSAGES_PATH, $request->toArray());
        return CompletionResponse::fromArray($data);
    }

    /**
     * 发送文本生成请求（流式模式）
     */
    public function sendCompletionMessageStream(CompletionRequest $request, CompletionStreamCallback $callback): void
    {
        // 确保请求模式为流式
        $requestData = $request->toArray();
        $requestData['response_mode'] = ResponseMode::STREAMING;

        try {
            $response = $this->httpClient->request('POST', $this->baseUrl . self::COMPLETION_MESSAGES_PATH, [
                'json' => $requestData,
                'stream' => true,
                'headers' => [
                    'Accept' => 'text/event-stream',
                ]
            ]);

            $this->processStreamResponse($response, $callback);
        } catch (GuzzleException $e) {
            $callback->handleException($e);
        }
    }

    /**
     * 停止文本生成
     */
    public function stopCompletion(string $taskId, string $user): SimpleResponse
    {
        $data = $this->executePost(
            self::COMPLETION_MESSAGES_PATH . '/' . $taskId . self::STOP_PATH,
            ['user' => $user]
        );
        return SimpleResponse::fromArray($data);
    }

    /**
     * 文字转语音
     */
    public function textToAudio(?string $messageId, ?string $text, string $user): string
    {
        $body = ['user' => $user];

        if ($messageId !== null) {
            $body['message_id'] = $messageId;
        }
        if ($text !== null) {
            $body['text'] = $text;
        }

        $response = $this->httpClient->request('POST', $this->baseUrl . self::TEXT_TO_AUDIO_PATH, [
            'json' => $body,
        ]);

        return $response->getBody()->getContents();
    }

    /**
     * 处理流式响应
     */
    private function processStreamResponse($response, CompletionStreamCallback $callback): void
    {
        $body = $response->getBody();

        while (!$body->eof()) {
            $line = $body->readLine();

            if (empty(trim($line))) {
                continue;
            }

            if (strpos($line, 'data: ') === 0) {
                $data = substr($line, 6);
                $eventData = json_decode($data, true);

                if ($eventData !== null) {
                    $event = EventFactory::create($eventData['event'] ?? 'unknown', $eventData);
                    $this->dispatchEvent($event, $callback);
                }
            } elseif (strpos($line, 'event: ping') === 0) {
                $callback->handlePing(new \Kunfeng\Dify\Event\PingEvent());
            }
        }
    }

    /**
     * 分发事件
     */
    private function dispatchEvent($event, CompletionStreamCallback $callback): void
    {
        switch (get_class($event)) {
            case \Kunfeng\Dify\Event\MessageEvent::class:
                $callback->handleMessage($event);
                break;
            case \Kunfeng\Dify\Event\MessageEndEvent::class:
                $callback->handleMessageEnd($event);
                break;
            case \Kunfeng\Dify\Event\TtsMessageEvent::class:
                $callback->handleTtsMessage($event);
                break;
            case \Kunfeng\Dify\Event\TtsMessageEndEvent::class:
                $callback->handleTtsMessageEnd($event);
                break;
            case \Kunfeng\Dify\Event\MessageReplaceEvent::class:
                $callback->handleMessageReplace($event);
                break;
            case \Kunfeng\Dify\Event\ErrorEvent::class:
                $callback->handleError($event);
                break;
        }
    }
}
